_Pragma("once");

#include <system_error>
#include <cstdio>
#include "Utility.h"
#include "StringUtility.h"


using FirmwareException = std::system_error;

#define BUILD_EXCEPTION(CODE) FirmwareException(static_cast<int>(CODE),  firmwareCategory, #CODE)

#define BUILD_EXCEPTION_MESSAGE(CODE, MESSAGE) FirmwareException(static_cast<int>(CODE), firmwareCategory, MESSAGE)

#define BUILD_EXCEPTION_ERROR(SYSTEM_ERROR_CODE, RETURN_CODE, ERROR_CODE, PREFIX) {\
    std::string prefix{PREFIX};\
    prefix.append(1, ',').append(__FUNCTION__);\
    buildErrorMessage(RETURN_CODE, ERROR_CODE, prefix);\
    throw FirmwareException(static_cast <int>(SYSTEM_ERROR_CODE),  firmwareCategory, prefix);}


#define BUILD_EXCEPTION_PRINTF(CODE, FORMAT, ...) {\
char buffer[MAX_BUFFER_SIZE];\
snprintf(buffer, sizeof (buffer), FORMAT, __VA_ARGS__);\
throw FirmwareException(static_cast<int>(CODE),  firmwareCategory, buffer);}

std::string& buildErrorMessage(const int returnCode, const int errCode, std::string& prefix);


enum class FirmwareError {
    OPEN_SERIAL_FAILED = 1
    ,LOOP_COUNT_NO_MATCH
    ,LOOP_SWITCH_FAILED
    ,CHANNEL_COMM_ERROR
    ,DOOR_ALERTOR_ERROR
    ,AC_SWITCH_DETECTOR_ERROR
    ,NETWORK_SIGNAL_ERROR
    ,JSON_BUILD_ERROR
    ,VIDEO_PLAY_ERROR
    ,HTTP_HEADER_ERROR
    ,UPDATE_FIRMWARE_ERROR
    ,UPDATE_PASSWORD_ERROR
    ,UPLOAD_OFFLINE_SYSTEM_INFO_ERROR
    ,DEVICE_MODULE_OFFLINE_ERROR
    ,IOTGATWAY_COMMAND_ERROR
    ,NET_INTERFACE_CONFIGURE_ERROR
};

extern std::string  firmwareErrorDesc[];


// custom category:
class FirmwareCategory : public std::error_category {
public:
  virtual const char* name() const noexcept { return "firmware system error"; }
  virtual std::error_condition default_error_condition (const int ev) const noexcept {
    return std::error_condition(ev, *this);
  }

  virtual std::string message(int ev) const noexcept {
        return firmwareErrorDesc[ev];
  }
};




extern FirmwareCategory  firmwareCategory;


